const jwt = require('jsonwebtoken');
const { verifyToken } = require('../config/jwt');
const User = require('../models/User');
const { AppError, catchAsync } = require('../utils/errorHandler');

/**
 * 保护路由中间件
 * 验证用户是否已登录
 */
exports.protect = catchAsync(async (req, res, next) => {
  // 1) 获取令牌
  let token;
  if (
    req.headers.authorization &&
    req.headers.authorization.startsWith('Bearer')
  ) {
    token = req.headers.authorization.split(' ')[1];
  } else if (req.cookies && req.cookies.jwt) {
    token = req.cookies.jwt;
  }

  if (!token) {
    return next(new AppError('您未登录，请登录后访问', 401));
  }

  // 2) 验证令牌
  const decoded = jwt.verify(token, process.env.JWT_SECRET);

  // 3) 检查用户是否仍然存在
  const currentUser = await User.findById(decoded.id);
  if (!currentUser) {
    return next(new AppError('此令牌的用户不再存在', 401));
  }

  // 4) 检查用户是否在令牌签发后更改了密码
  if (currentUser.passwordChangedAt) {
    const changedTimestamp = parseInt(
      currentUser.passwordChangedAt.getTime() / 1000,
      10
    );

    if (decoded.iat < changedTimestamp) {
      return next(new AppError('用户最近更改了密码，请重新登录', 401));
    }
  }

  // 5) 检查用户是否处于活动状态
  if (!currentUser.isActive) {
    return next(new AppError('此用户账号已被禁用', 403));
  }

  // 将用户信息添加到请求对象
  req.user = currentUser;
  next();
});

/**
 * 限制角色访问中间件
 * 限制特定角色的用户访问
 * @param  {...String} roles 允许访问的角色
 */
exports.restrictTo = (...roles) => {
  return (req, res, next) => {
    // roles ['admin', 'teacher']
    if (!roles.includes(req.user.role)) {
      return next(new AppError('您没有权限执行此操作', 403));
    }

    next();
  };
};

/**
 * 可选保护中间件
 * 如果有令牌，验证并添加用户信息；如果没有，继续处理
 */
exports.optionalProtect = catchAsync(async (req, res, next) => {
  // 1) 获取令牌
  let token;
  if (
    req.headers.authorization &&
    req.headers.authorization.startsWith('Bearer')
  ) {
    token = req.headers.authorization.split(' ')[1];
  } else if (req.cookies && req.cookies.jwt) {
    token = req.cookies.jwt;
  }

  if (!token) {
    return next(); // 没有令牌，继续处理
  }

  try {
    // 2) 验证令牌
    const { valid, expired, decoded } = verifyToken(token);

    if (!valid || expired) {
      return next(); // 令牌无效或已过期，继续处理
    }

    // 3) 检查用户是否仍然存在
    const currentUser = await User.findById(decoded.id);
    if (!currentUser || !currentUser.isActive) {
      return next(); // 用户不存在或已禁用，继续处理
    }

    // 将用户信息添加到请求对象
    req.user = currentUser;
    next();
  } catch (error) {
    next(); // 出现错误，继续处理
  }
});